#import "MapAppSettings.h"

// Shared instance of MapAppSettings
static MapAppSettings* sharedSettings = nil;

/**
 * A MapAppSettings is an object containing all the persistent
 * user-customizable settings for this application.
 *
 * @author      James Lin
 * @author      Justin Hollander
 * @version     2.2.5
 * @since       1.1.0
 */
@implementation MapAppSettings

@synthesize path;
@synthesize dirUpdateTimestamp;
@synthesize eventCacheInterval;
@synthesize currentMapType;
@synthesize foursquareVenueLimit;
@synthesize foursquareTipLimit;
@synthesize campus;

/**
 * Retrieve the shared instance of the application settings.
 *
 * @return  the shared instance of MapAppSettings
 */
+ (MapAppSettings*)sharedSettings {
	@synchronized (self) {
		if (sharedSettings == nil) {
			sharedSettings = [[MapAppSettings alloc] init];
		}
		return sharedSettings;
	}
}

/**
 * Allocate the application settings.
 *
 * @return  the newly allocated shared instance of MapAppSettings
 */
+ (id) alloc {
	@synchronized (self) {
		sharedSettings = [super alloc];
		return sharedSettings;
	}
}

/**
 * Retrieve a copy of the application settings.
 *
 * @return  the shared instance of MapAppSettings
 */
+ (id) copy {
	@synchronized (self) {
		return sharedSettings;
	}
}

/**
 * Initialize the application settings.
 * 
 * If the settings file at the path is non-existent, a default one is created.
 *
 * @precondition  the file at the path is valid or non-existent
 * @return        the initialized MapAppSettings
 */
- (id)init {
	if (self = [super init]) {
		NSFileManager* fileManager = [NSFileManager defaultManager];
		
		// Get the absolute path for the settings archive
		self.path = [FileUtilities getPathWithFileName:SETTINGS_FILENAME 
									 usingSubdirectory:SETTINGS_SUBDIRECTORY];
		if ([fileManager fileExistsAtPath:path]) {
			[self loadSettings];
		} else {
			[self setDefault];
		}
	}
	
	return self;
}

/**
 * Reset the application settings to default.
 */
- (void)setDefault {
	self.currentMapType = DEFAULT_MAP_TYPE;
	self.eventCacheInterval = DEFAULT_EVENT_CACHE_INTERVAL;
	self.foursquareVenueLimit = DEFAULT_FOURSQUARE_VENUE_LIMIT;
	self.foursquareTipLimit = DEFAULT_FOURSQUARE_TIP_LIMIT;
	self.campus = DEFAULT_CAMPUS;
	
	[self saveSettings];
}

/**
 * Save the application settings data to archive.
 */
- (void)saveSettings {
	NSMutableDictionary *rootObject = [NSMutableDictionary dictionary];
	[rootObject setValue:sharedSettings forKey:SETTINGS_ARCHIVE_KEY];
	[NSKeyedArchiver archiveRootObject:rootObject toFile:path];
}

/**
 * Load the application settings data from archive.
 */
- (void)loadSettings {
	NSMutableDictionary* rootObject;
	rootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
	sharedSettings = [[rootObject valueForKey:SETTINGS_ARCHIVE_KEY] retain];
	self.currentMapType = sharedSettings.currentMapType;
	self.eventCacheInterval = sharedSettings.eventCacheInterval;
	self.dirUpdateTimestamp = sharedSettings.dirUpdateTimestamp;
	self.foursquareVenueLimit = sharedSettings.foursquareVenueLimit;
	self.foursquareTipLimit = sharedSettings.foursquareTipLimit;
	self.campus = sharedSettings.campus;
	
	if (!(self.currentMapType >= 0)) {
		self.currentMapType = DEFAULT_MAP_TYPE;
	}
	if (!(self.eventCacheInterval > 0)) {
		self.eventCacheInterval = DEFAULT_EVENT_CACHE_INTERVAL;
	}
	if (!(self.foursquareVenueLimit > 0)) {
		self.foursquareVenueLimit = DEFAULT_FOURSQUARE_VENUE_LIMIT;
	}
	if (!(self.foursquareTipLimit > 0)) {
		self.foursquareTipLimit = DEFAULT_FOURSQUARE_TIP_LIMIT;
	}
	if (!(self.campus >= 0)) {
		self.campus = DEFAULT_CAMPUS;
	}
}

/**
 * Compute a unique key for the application settings.
 *
 * @return  the unique key for the application settings
 * @see     PersistentDataType
 */
- (NSString*)getKey {
	return @"MapAppSettingsKey";
}

/**
 * Encodes the application settings for archiving options.
 *
 * @param coder  the NSCoder used for encoding
 * @see          PersistentDataType
 */
- (void)encodeWithCoder:(NSCoder*)coder {
	if ([coder allowsKeyedCoding]) {
		[coder encodeInt:self.currentMapType forKey:@"CurrentMapType"];
		[coder encodeDouble:self.eventCacheInterval forKey:@"EventCacheInterval"];
		[coder encodeObject:self.dirUpdateTimestamp forKey:@"DirUpdateTimestamp"];
		[coder encodeInt:self.foursquareVenueLimit forKey:@"FoursquareVenueLimit"];
		[coder encodeInt:self.foursquareTipLimit forKey:@"FoursquareTipLimit"];
		[coder encodeInt:self.campus forKey:@"Campus"];
	}
}

/**
 * Initializes the application settings from archive.
 *
 * @param coder  the NSCoder used for decoding
 * @return       the application settings decoded from archive
 * @see          PersistentDataType
 */
- (id)initWithCoder:(NSCoder*)coder {
	if (self) {
		self.currentMapType = [coder decodeIntForKey:@"CurrentMapType"];
		self.eventCacheInterval = [coder decodeDoubleForKey:@"EventCacheInterval"];
		self.dirUpdateTimestamp = [coder decodeObjectForKey:@"DirUpdateTimestamp"];
		self.foursquareVenueLimit = [coder decodeIntForKey:@"FoursquareVenueLimit"];
		self.foursquareTipLimit = [coder decodeIntForKey:@"FoursquareTipLimit"];
		self.campus = [coder decodeIntForKey:@"Campus"];
	}
	
	return self;
}

/**
 * Deallocate the shared instance of the application settings.
 */
- (void)dealloc {
	[path release];
	path = nil;
	[dirUpdateTimestamp release];
	dirUpdateTimestamp = nil;
	[sharedSettings release];
	sharedSettings = nil;
	[super dealloc];
}

@end
